package com.lagou.sqlSession;


import com.lagou.config.BoundSql;
import com.lagou.pojo.Configuration;
import com.lagou.pojo.MappedStatement;
import com.lagou.utils.DefaultResultHander;
import com.lagou.utils.GenericTokenParser;
import com.lagou.utils.ParameterMapping;
import com.lagou.utils.ParameterMappingTokenHandler;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class simpleExecutor implements  Executor {
    private HashMap<String,List> selectCache=new HashMap<>();

    @Override                                                                                //user
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... params) throws Exception {
        // 1. 注册驱动，获取连接
        Connection connection = configuration.getDataSource().getConnection();

        // 2. 获取sql语句 : select * from user where id = #{id} and username = #{username}
            //转换sql语句： select * from user where id = ? and username = ? ，转换的过程中，还需要对#{}里面的值进行解析存储
        String sql = mappedStatement.getSql();
        BoundSql boundSql = getBoundSql(sql);

        // 3.获取预处理对象：preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getSqlText());
        //为了便于调试将sql打印出来
        System.out.println("sql 是"+boundSql.getSqlText());
        // 4. 设置参数
            //获取到了参数的全路径
         String paramterType = mappedStatement.getParamterType();
         Class<?> paramtertypeClass = getClassType(paramterType);

        List<ParameterMapping> parameterMappingList = boundSql.getParameterMappingList();

        String complatesql =boundSql.getSqlText();
        for (int i = 0; i < parameterMappingList.size(); i++) {
            ParameterMapping parameterMapping = parameterMappingList.get(i);
            String content = parameterMapping.getContent();

            //反射
            Field declaredField = paramtertypeClass.getDeclaredField(content);
            //暴力访问
            declaredField.setAccessible(true);
            Object o = declaredField.get(params[0]);
            complatesql +=o;


            preparedStatement.setObject(i+1,o);

        }
        System.out.println("complatesql===="+complatesql);



        // 5. 执行sql
        // 当不是查询操作是执行的sql应该是executeUpdate()所以进行修改根据sql命令不同今日不同sql执行

        ArrayList<Object> objects = new ArrayList<>();

        if(mappedStatement.getSqlCommondType().equals("select")){
            if (selectCache.get(complatesql)!=null){
                return selectCache.get(complatesql);
            }
            System.out.println("执行查询");
            ResultSet resultSet = preparedStatement.executeQuery();

            String resultType = mappedStatement.getResultType();

            DefaultResultHander defaultResultHander = new DefaultResultHander();
            objects =(ArrayList<Object> ) defaultResultHander.handerResultSet(resultSet, mappedStatement,configuration);


        }
        else {
            //更新，插入，删除均进入此sql  ===》遇到问题删除不掉带外建的数据
            preparedStatement.executeUpdate();
            selectCache.clear();

        }
       //将查询结果写入当前执行器缓存
       selectCache.put(complatesql, objects);

            return (List<E>) objects;

    }

    private Class<?> getClassType(String paramterType) throws ClassNotFoundException {
        if(paramterType!=null){
            Class<?> aClass = Class.forName(paramterType);
            return aClass;
        }
         return null;

    }


    /**
     * 完成对#{}的解析工作：1.将#{}使用？进行代替，2.解析出#{}里面的值进行存储
     * @param sql
     * @return
     */
    private BoundSql getBoundSql(String sql) {
        //标记处理类：配置标记解析器来完成对占位符的解析处理工作
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        //解析出来的sql
        String parseSql = genericTokenParser.parse(sql);
        //#{}里面解析出来的参数名称
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();

        BoundSql boundSql = new BoundSql(parseSql,parameterMappings);
         return boundSql;

    }


}
